package com.aity.hisse;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.log4j.Logger;

public class MyProxySelector extends ProxySelector {
	
	static Logger log = Logger.getLogger(MyProxySelector.class.getName());
	
	ProxySelector defsel = null;
	
    /*
     * Inner class representing a Proxy and a few extra data
     */
    class InnerProxy {
    Proxy proxy;
            SocketAddress addr;
            // How many times did we fail to reach this proxy?
            int failedCount = 0;
            
            InnerProxy(InetSocketAddress a) {
                    addr = a;
                    proxy = new Proxy(Proxy.Type.HTTP, a);
            }
            
            SocketAddress address() {
                    return addr;
            }
            
            Proxy toProxy() {
                    return proxy;
            }
            
            int failed() {
                    return ++failedCount;
            }
    }
	
    /*
     * A list of proxies, indexed by their address.
     */
    HashMap<SocketAddress, InnerProxy> proxies = new HashMap<SocketAddress, InnerProxy>();

    MyProxySelector(ProxySelector def) {
    	// Save the previous default
    	defsel = def;
      
    	//Populate the HashMap (List of proxies)
    	InnerProxy i = new InnerProxy(new InetSocketAddress("http-proxy.nbc.ge.com", 80));
    	proxies.put(i.address(), i);
    }
      

	@Override
	public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
		// Let's stick to the specs again.
        if (uri == null || sa == null || ioe == null) {
                throw new IllegalArgumentException("Arguments can't be null.");
        }
        
        log.info("Connection Failed" + sa);
        /*
         * Let's lookup for the proxy 
         */
        InnerProxy p = proxies.get(sa); 
        if (p != null) {
        	/*
        	 * It's one of ours, if it failed more than 3 times
        	 * let's remove it from the list.
        	 */
        	log.debug("The connection failed");
        	if (p.failed() >= 3){
        		proxies.remove(sa);
        		log.debug("We just removed the proxy from the list updated");
            }else {
            	/*
                 * Not one of ours, let's delegate to the default.
                 */
            	if (defsel != null){
            		log.debug("Just about to pass the default connection failed method");
            		defsel.connectFailed(uri, sa, ioe);
            	}
			}            
        }
	}

	@Override
	public List<Proxy> select(URI uri) {
		// Let's stick to the specs. 
        if (uri == null) {
                throw new IllegalArgumentException("URI can't be null.");
        }
        
        /*
         * If it's a http (or https) URL, then we use our own list.
         */
        String protocol = uri.getScheme();
        if ("http".equalsIgnoreCase(protocol) || "https".equalsIgnoreCase(protocol)) {
                ArrayList<Proxy> l = new ArrayList<Proxy>();
                for (InnerProxy p : proxies.values()) {
                	l.add(p.toProxy());
                	log.debug("We just added the proxy to the list returned by the select");
                }
                //l.add(Proxy.NO_PROXY);
                return l;
        }
        
        /*
         * Not HTTP or HTTPS (could be SOCKS or FTP)
         * defer to the default selector.
         */
        if (defsel != null) {
        	return defsel.select(uri);
        } else {
        	ArrayList<Proxy> l = new ArrayList<Proxy>();
        	l.add(Proxy.NO_PROXY);
        	return l;
        }
	}

///**
//* @param args
//*/
//public static void main(String[] args) {
// //TODO Auto-generated method stub
//
//	}

}
